import { filter, map, get, initial, last, reduce, isNil } from "lodash";
import React, { useMemo, useState, useEffect, useRef } from "react";
import ReactDOM from 'react-dom';
import PropTypes from "prop-types";
import Table from "antd/lib/table";
import Input from "antd/lib/input";
import Button from "antd/lib/button";
import InfoCircleFilledIcon from "@ant-design/icons/InfoCircleFilled";
import Popover from "antd/lib/popover";
import { RendererPropTypes } from "@/visualizations/prop-types";
import { prepareColumns, initRows, filterRows, sortRows } from "./utils";

import "./renderer.less";

function joinColumns(array, separator = ", ") {
  return reduce(
    array,
    (result, item, index) => {
      if (index > 0) {
        result.push(separator);
      }
      result.push(item);
      return result;
    },
    []
  );
}

function getSearchColumns(columns, { limit = Infinity, renderColumn = col => col.title } = {}) {
  const firstColumns = map(columns.slice(0, limit), col => renderColumn(col));
  const restColumns = map(columns.slice(limit), col => col.title);
  if (restColumns.length > 0) {
    return [...joinColumns(firstColumns), ` 和其 ${restColumns.length} 项内容`];
  }
  if (firstColumns.length > 1) {
    return [...joinColumns(initial(firstColumns)), ` 和 `, last(firstColumns)];
  }
  return firstColumns;
}

function SearchInputInfoIcon({ searchColumns }) {
  return (
    <Popover
      arrowPointAtCenter
      placement="topRight"
      content={
        <div className="table-visualization-search-info-content">
          搜索 {getSearchColumns(searchColumns, { renderColumn: col => <code key={col.name}>{col.title}</code> })}
        </div>
      }>
      <InfoCircleFilledIcon className="table-visualization-search-info-icon" />
    </Popover>
  );
}

function SearchInput({ searchColumns, ...props }) {
  if (searchColumns.length <= 0) {
    return null;
  }

  const searchColumnsLimit = 3;
  return (
    <Input.Search
      {...props}
      placeholder={`搜索 ${getSearchColumns(searchColumns, { limit: searchColumnsLimit }).join("")}...`}
      suffix={searchColumns.length > searchColumnsLimit ? <SearchInputInfoIcon searchColumns={searchColumns} /> : null}
    />
  );
}

SearchInput.propTypes = {
  onChange: PropTypes.func,
};

SearchInput.defaultProps = {
  onChange: () => {},
};

export default function Renderer({ options, data, onClickHandler, onCheckHandler, ...props }) {
  const [searchTerm, setSearchTerm] = useState("");
  const [orderBy, setOrderBy] = useState([]);
  const [selectedRowKeys, setSelectedRowKeys] = useState([]);
  const containerRef = useRef();

  const searchColumns = useMemo(() => filter(options.columns, "allowSearch"), [options.columns]);

  const tableColumns = useMemo(() => {
    const searchInput =
      searchColumns.length > 0 ? (
        <SearchInput searchColumns={searchColumns} onChange={event => setSearchTerm(event.target.value)} />
      ) : null;
    return prepareColumns(options.autoScroll, options.columns, searchInput, orderBy, newOrderBy => {
      setOrderBy(newOrderBy);
      // Remove text selection - may occur accidentally
      document.getSelection().removeAllRanges();
    }, {data, ...props});
  }, [options.columns, searchColumns, orderBy, data, props]);

  const preparedRows = useMemo(() => sortRows(filterRows(selectedRowKeys, options.columns[0].name, initRows(data.rows, options.columns[0].name, !!options.checkbox), searchTerm, searchColumns), orderBy), [
    options.columns,
    data.rows,
    selectedRowKeys,
    searchTerm,
    searchColumns,
    orderBy,
  ]);

  useEffect(() => {
    if (!options.autoScroll) return;

    let dom = ReactDOM.findDOMNode(containerRef.current);
    let tbody = dom.querySelector(".ant-table-tbody");  
    let timerRef = setInterval(scrollTop, (options.autoScrollSpeed || 1) * 1000);
    tbody.onmouseover = function() {clearInterval(timerRef);}  //鼠标移入，停止滚动
    tbody.onmouseout = function() {
      timerRef = setInterval(scrollTop, (options.autoScrollSpeed || 1) * 1000);
    }  //鼠标移出，继续滚动

    function scrollTop() {
      //将滚动的行追加到表格底部
      tbody.appendChild(tbody.removeChild(tbody.childNodes[0]));
    }
  }, [options.autoScroll, options.autoScrollSpeed]);
    
  // If data or config columns change - reset sorting
  useEffect(() => {
    setOrderBy([]);
  }, [options.columns, data.columns]);

  if (data.rows.length === 0) {
    return null;
  }

  const calcwidth = (options, index) => {
    var width = 0;
    if (index>=options.columns.length) index=options.columns.length-1;
    for (var i=0; i<=index; i++) {
      const iw = options.columns[i].width || '50px';
      width = width +  parseInt(iw); 
    }
    return width + 'px';
  }

  const showPortal = window.location.search.includes("show_portal") && localStorage.getItem('colorstyle_mode');
  const cssstyle = showPortal ? {
    "--style-color": localStorage.getItem('colorstyle_color'),
    "--style-bgcolor": options.bgColor || ((localStorage.getItem('colorstyle_back').length===9 || localStorage.getItem('colorstyle_back').length===7) ? localStorage.getItem('colorstyle_back').substr(0,7) : "#00000000"),
    "--style-titlecolor": options.titleColor || localStorage.getItem('colorstyle_color'),
    "--style-fixedbgcolor": options.fixedbgColor || '#F5F5F5',
    "--style-fixedtitlecolor": options.fixedtitleColor || localStorage.getItem('colorstyle_color'),
    "--style-fontsize": (options.fontsize || 12) + 'px',
    "--style-scroll": options.autoScroll && options.autoScrollBarHidden ? 'hidden' : 'auto',
    "--style-height": options.rowHeight,
    "--style-width0": calcwidth(options,0),
    "--style-width1": calcwidth(options,1),
    "--style-width2": calcwidth(options,2),
    "--style-width3": calcwidth(options,3),
    "--style-width4": calcwidth(options,4),
    "--style-width5": calcwidth(options,5),
  } : {
    "--style-fixedbgcolor": '#F5F5F5',
    "--style-fixedtitlecolor": 'black',
    "--style-fontsize": (options.fontsize || 12) + 'px',
    "--style-scroll": options.autoScroll && options.autoScrollBarHidden ? 'hidden' : 'auto',
    "--style-height": options.rowHeight,
    "--style-width0": calcwidth(options,0),
    "--style-width1": calcwidth(options,1),
    "--style-width2": calcwidth(options,2),
    "--style-width3": calcwidth(options,3),
    "--style-width4": calcwidth(options,4),
    "--style-width5": calcwidth(options,5),
  };  

  const getRowClassName = (record, index) => {
    let className = '';
    if (index % 2 === 0) className = "oddRow";
    return className
  }

  const loop = (cols, column) => {
    cols.forEach((item, index) => {
      if (item.children && item.children.length>0) {
        item.children = loop(item.children, column);
        cols.splice(index, 1, item);
      } else {
        if (item.key === column.key) {
          cols.splice(index, 1, column);
        } else {
          cols.splice(index, 1, item);
        }
      }
    });
    return cols;
  };

  const mergeHeader = () => {
    if (options && !!options.customCode) {
      var cols = [];
      var arrs = options.customCode.split(";");
      arrs.map((arr)=>{
        cols.push(JSON.parse(arr));
      });
      
      const oldcols = searchColumns.length > 0 ? tableColumns[0].children : tableColumns;

      oldcols.forEach((column)=>{
        if (column.key === "###Redash::Visualizations::Table::Spacer###")
          cols.push(column);
        else
          cols = loop(cols, column);
      })

      if (searchColumns.length > 0) {
        const rs = [...tableColumns];
        rs[0].children = [...cols];
        return rs;
      } else {
        return cols;
      }
    } else {
      return tableColumns;
    }
  }

  const onSelectChange = selectedRowKeys => {
    setSelectedRowKeys(selectedRowKeys);
  };

  const clearRowKeys = () => {
    setSelectedRowKeys([]);
  };

  const onCheckboxClick = () => {
    onCheckHandler(selectedRowKeys, clearRowKeys);
  }

  const rowSelection = {
    selectedRowKeys,
    onChange: onSelectChange,
    columnTitle: options.checkboxTitle && (<Button disabled={selectedRowKeys.length === 0} onClick={onCheckboxClick}>{options.checkboxTitle + '(' + selectedRowKeys.length + ')'}</Button>),
  };

  return (
    <div className="table-visualization-container" ref={containerRef}>
      <Table
        className={showPortal ? (
            options.hideGrid ? "table-header-border" : (!!options.customCode ? "table-dheader-custom" : "table-header-custom")
          ) : (
            options.hideGrid ? "table-border-header" : (!!options.customCode ? "table-fixed-dheader" : "table-fixed-header")
          )
        }
        rowClassName={options.rowOddEven ? (record, index) => getRowClassName(record, index) : ''}
        data-percy="show-scrollbars"
        data-test="TableVisualization"
        rowSelection={options.checkbox && rowSelection}
        columns={mergeHeader()}
        showHeader={!!options.hideHeader ? false : true}
        dataSource={preparedRows}
        style={cssstyle}
        pagination={(options.autoScroll || options.itemsPerPage===0) ? false : {
          size: get(options, "paginationSize", ""),
          position: "bottom",
          pageSize: options.itemsPerPage,
          hideOnSinglePage: true,
          showSizeChanger: false,
        }}
        showSorterTooltip={false}
        onRow={record => {
          return {
            onClick: event => {
              if (!options.clickEnabled) return;
              if (!!options.doubleClick) return;

              if (!!options.clickColumn) {
                let obj = {};
                options.clickColumn.split(",").forEach((key, i) => {
                  let value = record.record[key];
                  if (!!options.clickParameter && i < options.clickParameter.split(",").length) {
                    if (!!options.clickParameter.split(",")[i]) key = options.clickParameter.split(",")[i];
                  }
                  obj[key] = value;
                });
                onClickHandler(obj);
              }
            },
            onDoubleClick: event => {
              if (!options.clickEnabled) return;
              if (!options.doubleClick) return;

              if (!!options.clickColumn) {
                let obj = {};
                options.clickColumn.split(",").forEach((key, i) => {
                  let value = record.record[key];
                  if (!!options.clickParameter && i < options.clickParameter.split(",").length) {
                    if (!!options.clickParameter.split(",")[i]) key = options.clickParameter.split(",")[i];
                  }
                  obj[key] = value;
                });
                onClickHandler(obj);
              }
            },
            onContextMenu: event => {},
            onMouseEnter: event => {},
            onMouseLeave: event => {},
          };
        }}
      />
    </div>
  );
}

Renderer.propTypes = RendererPropTypes;
